	;; 此函数的主要功能是从指定扇区加载模块
	;; 而后运行模块内容

	%include "conf.inc"

	bits 16
	org BOOT_SEG
start:
	mov	ax, cs
	mov	ds, ax
	mov	ss, ax
	mov	es, ax
	mov	sp, BOOT_SEG

	call clear_screen

	call check_int13h_extension
	cmp  ax, 0h
	jz cont
	mov si, LoadFailedMsg
	call __puts
	ret
	
cont:	
	mov si, 1
	mov di, LOADER_SEG - 2
	call read_sector_extension
	
	mov si, LOADER_SEG - 2
	mov cx, 0100h
	call __put_bytes
	
	xor bx, bx
	.dump:
	mov cx, 010h
	mov ax, 010h
	mul bx
	add ax, LOADER_SEG
	mov dx, ax
	call __put_word
	mov si, ':'
	call __putc
	mov si, ' '
	call __putc
	mov si, dx
	call __put_bytes
	call __println
	inc bx
	cmp bx, 010h
	jnz .dump

exit:
	jmp $	
	
;--------------------------------
; puts(): 打印字符串信息
; input: 
;		al: message
;--------------------------------
__put_byte:
	pusha
	mov   bl, al
	movzx si, bl
	and si, 000f0h
	shr si, 4
	call __hex_to_char
	mov si, ax
	call __putc

	movzx si, bl
	and si, 0000fh
	call __hex_to_char
	mov si, ax
	call __putc

	mov si, 20h
	call __putc
	popa
	ret

__put_word:
	pusha
	mov bx, ax
	shr ax, 8
	call __put_byte

	mov ax, bx
	call __put_byte
	
	popa
	ret

;-------------------------------
; put_bytes(char* buffer, int size)
; si:buffer
; cx: size
;-------------------------------
__put_bytes:
	pusha
	.loop:
	lodsb
	call __put_byte
	loop .loop
	
	popa
	ret

;----------------------------------------------------------------------	
; read_sector(int sector, char *buf): read one floppy sector(LBA mode)
; input:  
;		si - sector
;		di - buf
;----------------------------------------------------------------------
read_sector:
	pusha
	push es
	push ds
	pop es

; 测试是否支持 int 13h 扩展功能
	call check_int13h_extension
	test ax, ax
	jz do_read_sector_extension		; 支持

	mov bx, di						; data buffer
	mov ax, si						; disk sector number
; now: LBA mode --> CHS mode	
	call LBA_to_CHS
; now: read sector	
%ifdef UBOOT
	mov dl, 0x80		; for U 盘或者硬盘
%else	
	mov dl, 0	; for floppy
%endif
	mov ax, 0x201
	int 0x13
	setc al		; 0: success  1: failure	
	jmp do_read_sector_done

; 使用扩展功能读扇区
do_read_sector_extension:
	call read_sector_extension
	mov al, 0
	
do_read_sector_done:	
	pop es
	popa
	movzx ax, al
	ret

;-------------------------------------------------------
; LBA_to_CHS(): LBA mode converting CHS	mode for floppy 
; input:
;		ax - LBA sector
; output:
;		ch - cylinder
;		cl - sector (1-63)
;		dh - head	
;-------------------------------------------------------
LBA_to_CHS:
	mov cl, SPT
	div cl	; al = LBA / SPT, ah = LBA % SPT
; cylinder = LBA / SPT / HPC
	mov ch, al
	shr ch, (HPC / 2); ch = cylinder
; head = (LBA / SPT ) % HPC
	mov dh, al
	and dh, 1	; dh = head
; sector = LBA % SPT + 1
	mov cl, ah
	inc cl		; cl = sector
	ret


;--------------------------------------------------------
; check_int13h_extension(): 测试是否支持 int13h 扩展功能
; ouput:
;		0 - support, 1 - not support
;--------------------------------------------------------
check_int13h_extension:
	push bx
	mov bx, 0x55aa
	mov ah, 0x41
	int 0x13
	setc al	; 失败
	jc do_check_int13h_extension_done
	cmp bx, 0xaa55
	setnz al	; 不支持
	jnz do_check_int13h_extension_done
	test cx, 1
	setz al	; 不支持扩展功能号：AH=42h-44h,47h,48h
do_check_int13h_extension_done:	
	pop bx
	movzx ax, al
	ret

;--------------------------------------------------------------
; read_sector_extension(): 使用扩展功能读扇区	
; input:
;		si - sector
;		di - buf (es:di)
;----------------------------------------------------------------------
read_sector_extension:
	xor eax, eax
	movzx esi, si
	push eax
	push esi		; 要读的扇区号 (LBA) - 64 位值
	push es
	push di			; buf 缓冲区 es:di - 32 位值
	push word 0x01		; 扇区数, word
	push word 0x10		; 结构体 size, 16 bytes
	
	mov ah, 0x42		; 扩展功能号
%ifdef UBOOT
	mov dl, 0x80
%else
	mov dl, 0
%endif		
	mov si, sp		; 输入结构体地址
	int 0x13	
	add sp, 0x10
	ret

;-------------------------------------------------------------------
; load_module(int module_sector, char *buf):  加载模块到 buf 缓冲区
; input:
;                esi: module_sector 模块的扇区
;                di: buf 缓冲区
; example:
;                load_module(SETUP_SEG, SETUP_SECTOR);
;-------------------------------------------------------------------
load_module:
        call read_sector                          ; read_sector(sector, buf)
        test ax, ax
        jnz do_load_module_done
        
        mov cx, [di]                              ; 读取模块 size
        test cx, cx
        setz al
        jz do_load_module_done
        add cx, 512 - 1
        shr cx, 9                                 ; 计算 block（sectors）
  
do_load_module_loop:  
;        call dot
        dec cx
        jz do_load_module_done 
        inc esi
        add di, 0x200
        call read_sector
        test ax, ax
        jz do_load_module_loop

do_load_module_done:  
        ret

;------------------------------------------------------
; clear_screen()
; description:
;		clear the screen & set cursor position at (0,0)
;------------------------------------------------------
clear_screen:
	pusha
	mov ax, 0x0600
	xor cx, cx
	xor bh, 0x0f	; white
	mov dh,	24
	mov dl, 79
	int 0x10
	
set_cursor_position:
	mov ah, 02
	mov bh, 0
	mov dx, 0
	int 0x10	
	popa
	ret

;--------------------------------
; print_message()
; input: 
;		si: message
;--------------------------------
print_message:
	pusha
	mov 	ah, 0x0e
	xor 	bh, bh	

do_print_message_loop:	
	lodsb
	test 	al,al
	jz 	do_print_message_done
	int 	0x10
	jmp 	do_print_message_loop

do_print_message_done:	
	popa
	ret

;--------------------------------
; putc(): 打印一个字符
; input: 
;		si: char
;--------------------------------
__putc:
	push bx
	xor bh, bh
	mov ax, si
	mov ah, 0x0e		
	int 0x10
	pop bx
	ret

;--------------------------------
; println(): 打印换行
;--------------------------------
__println:
	mov si, 13
	call __putc
	mov si, 10
	call __putc
	ret

;--------------------------------
; puts(): 打印字符串信息
; input: 
;		si: message
;--------------------------------
__puts:
	pusha
	mov ah, 0x0e
	xor bh, bh	

do_puts_loop:	
	lodsb
	test al,al
	jz do_puts_done
	int 0x10
	jmp do_puts_loop

do_puts_done:	
	popa
	ret

;-----------------------------------------
; hex_to_char(): 将 Hex 数字转换为 Char 字符
; input:
;		si: Hex number
; ouput:
;		ax: Char
;----------------------------------------
__hex_to_char:
	jmp do_hex_to_char
@char	db '0123456789ABCDEF', 0

do_hex_to_char:	
	push si
	and si, 0x0f
	mov ax, [@char+si]
	pop si
	ret

BootMessage:	db 	"boot..."
LoadFailedMsg:	db 	"Failed to load module...", 13, 10, 0
LoadSuccessMsg:	db	"Success to load module...", 13, 10, 0
	times	510-($-$$) db 0
	dw 0xaa55